/**
 * @file VideoCapture.h
 * @author your name (you@domain.com)
 * @brief
 * @version 0.1
 * @date 2022-10-25
 *
 * @copyright Copyright (c) 2005-2022 XAG Co., Ltd. All Rights Reserved
 *
 */

#pragma once
#include <assert.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <linux/videodev2.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <atomic>
#include <condition_variable>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <thread>

#include <sys/timeb.h>  // NOLINT
#include "FileNameProduce.h"
#include "IVideoConsumer.h"
#include "ImageExifInfo/ImageExifInfo.h"
#include "TurboJpeg/TurboJpegComm.h"
#include "VideoIspPipe.h"
#include "im2d.hpp"        /* NOLINT */
#include "mpp_buffer.h"    /* NOLINT */
#include "mpp_frame.h"     /* NOLINT */
#include "rga.h"           /* NOLINT */
#include "rkmedia_api.h"   /* NOLINT */
#include "sample_common.h" /* NOLINT */
#include "utils/mpi_enc_test.h"
extern "C" {
#include "utils/rga_control.h"
#include "utils/vpu_encode.h"
}
// #include "VideoQueBuffer.h"
// #include "StereoCamV4L2Ctrl.h"
// #include "StereoShmIPC.h"
#define CAMERA_FRONT_ID 1
#define CAMERA_BOTTOM_ID 0
#define CMAERA_NUMNER 2

#define UPDATE_SYSTEM_MARK "/oem/private/system_update_mark"
#define HDR_SYSTEM_MARK "/oem/private/hdr_mode_mark"
#define THERMAL_ZONE_MARK "/sys/class/thermal/thermal_zone0/temp"

#define STD_IMG_SAVEPATH "/userdata/pic/"
#define CAL_IMG_SAVEPATH "/userdata/cal/"

#define CAM_FRONT_SNAP_IMAGEWIDTH 960
#define CAM_FRONT_SNAP_IMAGEHEIGH 540

#define CAM_BOTTOM_SNAP_IMAGEWIDTH 960
#define CAM_BOTTOM_SNAP_IMAGEHEIGH 540

// #define CAM_FRONT_SNAP_DEVNODE "/dev/video38"
// #define CAM_BOTTOM_SNAP_DEVNODE "/dev/video30"
#define CAM_FRONT_SNAP_DEVNODE "/dev/video40"
#define CAM_BOTTOM_SNAP_DEVNODE "/dev/video32"
// #define CAM_FRONT_SNAP_DEVNODE "/dev/video38"
// #define CAM_BOTTOM_SNAP_DEVNODE "/dev/video30"

#define CAM_FRONT_VISION_ENC_IMAGEWIDTH 960
#define CAM_FRONT_VISION_ENC_IMAGEHEIGH 480

#define CAM_BOTTOM_LIGHTFLOW_ENC_IMAGEWIDTH 640
#define CAM_BOTTOM_LIGHTFLOW_ENC_IMAGEHEIGH 384

#define CAM_BOTTOM_EIS_ENC_IMAGEWIDTH 1280
#define CAM_BOTTOM_EIS_ENC_IMAGEHEIGH 768

// #define CAM_FRONT_SNAP_DEVNODE "/dev/video38"
// #define CAM_BOTTOM_SNAP_DEVNODE "/dev/video30"

#define CAM_FRONT_SNAP_DEVNODE "/dev/video40"
#define CAM_BOTTOM_SNAP_DEVNODE "/dev/video32"

#define IQFILES_PATH "/oem/iqfiles"
#define BUFFER_COUNT 8
#define SYNC_BUFFER_COUNT 5
#define FMT_NUM_PLANES 1

// #define CAM_EsNC 1 /* NOLINT */

#define SNAPFLAG_PATH "/oem/snap.flag"
#define HRTIMER_SYNC_DEV "/dev/hrtimer_sync"

#define CAM_FRONT_SUBDEVNODE "/dev/v4l-subdev4"
#define CAM_BOTTOM_SUBDEVNODE "/dev/v4l-subdev11"

#define V4L2_CID_EXPOSURE_NEWMAX (V4L2_CID_USER_BASE + 0x1050)
#define V4L2_CID_EXPOSURE_NEWMIN (V4L2_CID_USER_BASE + 0x1080)
#define V4L2_CID_GAIN_NEWMAX (V4L2_CID_USER_BASE + 0x1060)
#define V4L2_CID_DGAIN_NEWMAX (V4L2_CID_USER_BASE + 0x1070)
#define RK_SAVE_JPEG 1
#define SEND_YUV_TODEAL_TEST
#define RK_SAVE_YUV 1
#define SYNC_INFO 1
#define CLEAR(x) memset(&(x), 0, sizeof(x))
#define ERR(...)                      \
    do {                              \
        fprintf(stderr, __VA_ARGS__); \
    } while (0)

// 获取IMU数据
extern int g_hwtimer_sync_fd;
#define IMU_COUT_MAX 40

namespace kapok_hardware_rv1126 {

typedef struct CamFrame_st {
    void* start;
    size_t length;
    int export_fd;
    unsigned int sequence;    // frame num
    unsigned long timestamp;  // frame timestimp /* NOLINT */
    MppBuffer buffer;
} CamFrame_S;

typedef struct CamSource_st {
    int fd;      // Device handle
    int subfd;   // Device handle
    int bufcnt;  // # of buffers
    enum v4l2_buf_type type;
    MppFrameFormat fmt;
    CamFrame_S fbuf[10];  // frame buffers
    int s32CurIndex;
} CamSource_S;

enum SNAPSATUS {
    SNAPWAIT,     // 抓拍等待
    SNAPING,      // 抓拍进行中
    SNAPTRIGETR,  // 抓拍触发
};

struct icm42686_data {
    unsigned long long sys_timestamp;  // NOLINT
    struct _acc {
        unsigned short x;  // NOLINT
        unsigned short y;  // NOLINT
        unsigned short z;  // NOLINT
    } acc;

    struct _gyro {
        unsigned short x;  // NOLINT
        unsigned short y;  // NOLINT
        unsigned short z;  // NOLINT
    } gyro;
};

typedef struct camera_info {
    unsigned long long exp_timestamp_us;  // NOLINT //同步时间戳
    unsigned short exp_value;  // NOLINT // 线性曝光值,HDR长曝光值
    unsigned short exp_short_value;  // NOLINT // HDR短曝光值
    unsigned short again_value;  // NOLINT //线性模拟增益,HDR长曝光模拟增益
    unsigned short again_short_value;  // NOLINT //HDR短曝光模拟增益
    unsigned short dgain_value;  // NOLINT //线性数字增益,HDR短曝光数字增
    unsigned short dgain_short_value;  // NOLINT //HDR短曝光模拟增益
    unsigned char sync_info;           // NOLINT
} APP_FRAME_SERSON_SYNC_INFO;

// 应用查询同步信息数据结构
typedef struct app_frame_imu_sync_info {
    unsigned char type;  // 查询使用 0 下视 1前视
    unsigned char sync;  // 0 没有同步  1 同步下视IMU  2同步前视IMU
    int framemode;       // 0 视频帧 1 拍照帧
    unsigned int frame_sequence;               // 帧号
    unsigned long long frame_timestamp;        // 相对时间戳 // NOLINT
    unsigned long long frame_systimestamp;     // 系统时间戳 // NOLINT
    unsigned long long frame_systimestamp_us;  // 系统时间戳 // NOLINT
    struct icm42686_data imu_frontdata[IMU_COUT_MAX];   // 前视MU数据值
    struct icm42686_data imu_bottomdata[IMU_COUT_MAX];  // 后视IMU数据值
    int imu_count;                                      // IMU个数
    int snap_count;                                     // 拍照触发次数
    struct camera_info sensor_frontdata;
    struct camera_info sensor_bottomdata;
    long int time_offset;  // NOLINT
} APP_FRAME_IMU_SYNC_INFO;

typedef struct SanpSync_st {
    char filepath[100];
    APP_FRAME_IMU_SYNC_INFO imu_sync_info;
} SanpSyncInfo_S;

typedef struct ASanpSync_st {
    AsyncSnapInfo_ST async_Info;  // 异步拍照使用,用于回传数据
    int async_flag;               // 异步模式 同步情况 2:两个完成
    std::string async_filepath[CMAERA_NUMNER];
} ASanpSyncInfoFlag_S;

#define SANP_SYNCMODE 0
#define SANP_ASYNCMODE 1

#define IOCTL_BASE 'S'
#define SC230AI_SYNC_CMD \
    _IOWR(IOCTL_BASE, 0, int)  // 读命令, 带参char*, 自定义0为命令编号不可重复
#define SC230AI_IMU_TIMESTAMP_QUERY_CMD \
    _IOWR(IOCTL_BASE, 1, APP_FRAME_IMU_SYNC_INFO)
#define SC230AI_SANP_CMD \
    _IOWR(IOCTL_BASE, 2, int)  // 命令, 带参char*, 自定义0为命令编号不可重复
#define SC230AI_SYNC_HDR_CMD \
    _IOWR(IOCTL_BASE, 3, int)  // 命令, 带参char*, 自定义0为命令编号不可重复

struct ReleaseInfo_ST {
    uint8_t* m_pu8Data = nullptr;
    int32_t m_s32Size = 0;
};

class VideoCapture {
   public: /* NOLINT */
    bool Init(void);

    bool Uninit(void);

    static int xioctl(int fh, int request, void* arg);

    int RkIspRoutine();

    void Rk_Ispv4l2_exit(CamSource_S* objCamSoure);

    int RkV4l2_Init_Device(CamSource_S* objCamSoure,
                           const char* node,
                           int index,
                           int width,
                           int height);

    int Init_Mmap(CamSource_S* objCamSoure, const char* node);

    int Start_Capturing(CamSource_S* objCamSoure, const char* node, int sync);

    void Stop_Capturing(CamSource_S* objCamSoure);

    void Sync_Init();

    int Rk_Ispv4l2_Get_Frame(CamSource_S* objCamSoure);

    static int Rk_Ispv4l2_Set_frame(CamSource_S* objCamSoure, RK_S32 idx);
    // 硬件缩放
    int RK_Rga_Resize(
        unsigned char* src,
        int fd,
        unsigned char* dst,
        int dst_fd,
        int width,
        int height,
        int _s32DestW,
        int s32DestH,
        int warpfd = 0);  // NOLINT warpfd 0:默认使用底层连续内存加速 1,不使用

    int RK_Rga(unsigned char* src_buf,
               unsigned char* dst_buf,
               int width,
               int height);

        int32_t SendSyncData(int32_t _s32Index,
                             int32_t _s32Buf,
                             uint8_t* _pImu,
                             uint32_t _u32Size,
                             uint64_t _u64Time);

    void _GapDebug(int32_t _s32Index, uint64_t _u64Time);

    // 原图拍照流处理线程
    int WorkThread_Snap(void);
    // 原图拍照流处理同步线程
    int WorkThread_SnapSync(void);

    // 抓拍
    int Snap(const std::string& strFrontImgPath, int mode = SANP_SYNCMODE);

    // 异步抓拍
    bool AsyncSnap(AsyncSnapInfo_ST& _rInfo); /* NOLINT */

    int32_t ControlSensorProperty(SensorProperty_ST& _rProperty);  // NOLINT

    // int32_t SetSyncGap(int32_t _s32Down, int32_t _s32Front);
    // 温度更新
    int Thermal_Update();
    // 存储处理
    int ProcessSaveImg(int i,
                       int buf_index,
                       unsigned int snap_count,
                       APP_FRAME_IMU_SYNC_INFO& syncinfo);  // NOLINT

    std::string strImgPath[CMAERA_NUMNER];
    std::string strYuvImgPath[CMAERA_NUMNER];

    int m_hdr_mode = 0;

    CamSource_S m_objCamSnapSource[CMAERA_NUMNER];

   private: /* NOLINT */
    static std::atomic<bool> m_bInit;

    std::thread m_thdSnapWork;
    std::thread m_thdSnapSyncWork;

    bool m_thdSnapRunFlg = 0;
    bool m_thdSnapSyncRunFlg = 0;
    int m_SnapFlag;
    int m_snap_count = 0;
    int m_triger_flag[CMAERA_NUMNER] = {0};
    int m_snapyuv_count = 0;
    int m_snapyuv_saveid[CMAERA_NUMNER] = {0};
    int m_snapyuv_savefps[CMAERA_NUMNER] = {0};
    // 同步模式标记位
    // int m_hwtimer_sync_fd = 0;
    int m_hwtimer_snap_flag = 0;

    // 异步模式
    ASanpSyncInfoFlag_S m_AsyncSnapInfmode;
    std::map<int, ASanpSyncInfoFlag_S> m_MapAsyncSnapInfomode;

    unsigned long long last_frame_systimestamp[CMAERA_NUMNER];  // NOLINT
    unsigned long long last_frame_timestamp[CMAERA_NUMNER];     // NOLINT
    struct vpu_encode m_vpu_encode;
    bo_t m_vpu_enc_bo;
    bo_t m_vpu_rga_bo;
    int m_vpu_jpeg_fd;
    int m_vpu_rga_fd;

    // 抓拍YUV存储BUFF
    unsigned char* m_s8Yuvbuffer;
    int m_s8YuvbufferLen = 0;
    std::string m_strImgPath;
    std::string m_UUID;

    std::list<SanpSyncInfo_S> m_SnapSyncList;
    kapok_functionals::ImageExifInfo m_SnapSyncInfo;
    // 拍照照片文件名生成
    kapok_functionals::FileNameProduce m_objStdFileNnamePro;
    kapok_functionals::FileNameProduce m_objYuvFileNnamePro;

    // 控制裸流传输帧率
    std::mutex m_GapMutex; /* 锁设置 */
    int32_t m_s32DownGap = 1;
    int32_t m_s32FrontGap = 2;
    int32_t m_s32DownCount = 0;
    int32_t m_s32FrontCount = 0;
    int32_t m_s32DownW = 640;
    int32_t m_s32DownH = 360;
    int32_t m_s32FrontW = 960;
    int32_t m_s32FrontH = 540;
    uint64_t m_u64Gap = 0;
    uint64_t m_u64GapFront = 0;
};

}  // namespace kapok_hardware_rv1126
